package com.gitee.xzb617.mybatis.sqllog.executor;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 线程池
 * @author xuzhibin
 */
public class SqlLogAsyncExecutor {

    // 非核心线程闲置超时时间（毫秒）
    private static int KEEP_ALIVE_TIME = 1000;
    // 线程等待队列容量
    private static int THREAD_POOL_QUEUE_SIZE = 50000;

    // CPU 核心数
    private final static int CPU_CORE_NUMBER = Runtime.getRuntime().availableProcessors();

    // 管理器实例（线程可见）
    private static volatile SqlLogAsyncExecutor instance;

    // 线程池执行器
    private ThreadPoolExecutor executor;

    // 线程等待队列
    private static ArrayBlockingQueue THREAD_POOL_QUEUE =  new ArrayBlockingQueue<>(THREAD_POOL_QUEUE_SIZE);

    /**
     * 获取一个线程池
     * @return
     */
    public static ThreadPoolExecutor newThreadPoolExecutor() {
        return new ThreadPoolExecutor(
                CPU_CORE_NUMBER/3, (CPU_CORE_NUMBER/3)*2, KEEP_ALIVE_TIME,
                TimeUnit.MILLISECONDS, THREAD_POOL_QUEUE, new SqlLogAsyncExecutor.SqlLogThreadFactory("sql-log", true));
    }

    /**
     * 获取管理器单例
     * @return
     */
    public static SqlLogAsyncExecutor instance() {
        if (instance == null) {
            synchronized (SqlLogAsyncExecutor.class) {
                if (instance == null) {
                    instance = new SqlLogAsyncExecutor();
                    instance.executor = newThreadPoolExecutor();
                }
            }
        }
        return instance;
    }


    /**
     * 添加任务
     * @param task 任务
     * @return
     */
    public <T> Future<T> submit(Callable<T> task) {
        if (task == null) {
            throw new IllegalArgumentException("Unable to add an empty task to the thread pool for execution.");
        }
        // 提交任务
        return executor.submit(task);
    }

    /**
     * 添加任务
     * @param task 任务
     */
    public void execute(Runnable task) {
        if (task == null) {
            throw new IllegalArgumentException("Unable to add an empty task to the thread pool for execution.");
        }
        // 提交任务
        executor.execute(task);
    }


    /**
     * 自定义的线程工厂类
     * <b>Note </b> 主要是为了明确的指定线程名称
     * @author xzb
     */
    static class SqlLogThreadFactory implements ThreadFactory {
        private static final AtomicInteger poolNumber = new AtomicInteger(1);
        private final ThreadGroup group;
        private final AtomicInteger threadNumber = new AtomicInteger(1);
        private final String namePrefix;
        private final boolean daemon;

        SqlLogThreadFactory(String poolName, boolean daemon) {
            this.daemon = daemon;
            SecurityManager s = System.getSecurityManager();
            group = (s != null) ? s.getThreadGroup() :
                    Thread.currentThread().getThreadGroup();
            namePrefix = poolName + "-" +
                    poolNumber.getAndIncrement() +
                    "-thread-";
        }

        public Thread newThread(Runnable r) {
            Thread t = new Thread(group, r,
                    namePrefix + threadNumber.getAndIncrement(),
                    0);
            if (t.isDaemon())
                // 此处都设置为守护线程
                t.setDaemon(this.daemon);
            if (t.getPriority() != Thread.NORM_PRIORITY)
                t.setPriority(Thread.NORM_PRIORITY);
            return t;
        }
    }
}
